package adventure.placeable.trigger.results;

import adventure.misc.Currency;
import adventure.misc.CurrencyImp;
import adventure.placeable.trigger.conditions.TriggerCondition;
import adventure.room.RoomManager;
import colour.ColourUtil;
import java.util.ArrayList;
import player.Player;
import server.util.Broadcaster;
import server.util.BroadcasterImp;

/**
 *
 * @author Michael Hanns
 *
 */
public abstract class TriggerResult implements Cloneable {

    private Currency currencyType;
    private boolean limitedUses;
    private int usesRemaining;
    protected String resultText;
    private boolean publicResult;
    private ArrayList<TriggerCondition> conditions;
    
    private Broadcaster dummyOut;

    public TriggerResult(String result, int uses) {
        currencyType = new CurrencyImp();
        conditions = new ArrayList<TriggerCondition>();
        usesRemaining = uses;
        limitedUses = true;
        this.resultText = result;
        this.publicResult = true;
        this.dummyOut = new BroadcasterImp();
    }

    public TriggerResult(String result) {
        currencyType = new CurrencyImp();
        conditions = new ArrayList<TriggerCondition>();
        usesRemaining = 0;
        limitedUses = false;
        this.resultText = result;
        this.publicResult = true;
        this.dummyOut = new BroadcasterImp();
    }

    public TriggerResult() {
        currencyType = new CurrencyImp();
        conditions = new ArrayList<TriggerCondition>();
        usesRemaining = 0;
        limitedUses = false;
        resultText = "";
        this.publicResult = true;
        this.dummyOut = new BroadcasterImp();
    }
    

    public void setCurrencyType(Currency type) {
        currencyType = type;
    }

    public void setResultText(String result) {
        resultText = result;
    }

    public void setLimitedUses(boolean val) {
        limitedUses = val;
        if (!limitedUses) {
            usesRemaining = 0;
        }
    }

    public void setUses(int val) {
        usesRemaining = val;
    }
    
    public void setPublicResult(boolean val) {
        publicResult = val;
    }

    public String getResultText() {
        return resultText;
    }
    
    public boolean isPublicResult() {
        return publicResult;
    }

    public boolean limitedUses() {
        return limitedUses;
    }

    public int usesRemaining() {
        return usesRemaining;
    }

    protected void useOnce() {
        if (limitedUses && usesRemaining > 0) {
            usesRemaining--;
        }
    }

    public TriggerCondition[] getConditions() {
        TriggerCondition[] triggers = new TriggerCondition[conditions.size()];
        for (int x = 0; x < conditions.size(); x++) {
            triggers[x] = conditions.get(x);
        }
        return triggers;
    }

    public void setConditions(TriggerCondition[] newConds) {
        conditions = new ArrayList<TriggerCondition>();
        for (int x = 0; x < newConds.length; x++) {
            conditions.add(newConds[x]);
        }
    }

    public void moveConditionUp(int position) {
        if (position > 0) {
            TriggerCondition temp = conditions.get(position - 1);
            conditions.set(position - 1, conditions.get(position));
            conditions.set(position, temp);

        }
    }

    public void moveConditionDown(int position) {
        if (position < conditions.size() - 1) {
            TriggerCondition temp = conditions.get(position + 1);
            conditions.set(position + 1, conditions.get(position));
            conditions.set(position, temp);
        }
    }

    public void addCondition(TriggerCondition c) {
        conditions.add(c);
    }

    public void removeConditionAtIndex(int x) {
        if (x < conditions.size()) {
            conditions.remove(x);
        }
    }
    
    public String executeResult(RoomManager r, Player p, String i, boolean prevFailed, Broadcaster out) {
        if(publicResult) {
            return resultImplementation(r, p, i, prevFailed, out);
        } else {
            return resultImplementation(r, p, i, prevFailed, dummyOut);
        }
    }

    protected abstract String resultImplementation(RoomManager r, Player p, String i, boolean previousFailed, Broadcaster out);
    
    public abstract String getDescription();
    
    public boolean stillLive() {
        if (limitedUses == false) {
            return true;
        } else if (usesRemaining > 0) {
            return true;
        }
        return false;
    }

    protected boolean allConditionsMet(RoomManager r, Player p, String i, boolean previousFailed) {
        if(i != null && !isUserSpecified()) {
            return false;
        }
        
        for (int x = 0; x < conditions.size(); x++) {
            if (!conditions.get(x).meetsCondition(r, p, i, previousFailed)) {
                return false;
            }
        }
        return true;
    }
    
    protected boolean isUserSpecified() {
        for (int x = 0; x < conditions.size(); x++) {
            if (conditions.get(x).isUserSpecified()) {
                return true;
            }
        }
        return false;
    }

    public abstract String getType();

    public abstract String replaceKeywords(Player p);

    // At the moment, this can't take into account whether the room is dark or not
    protected String replaceCurrency(String text, int intMod) {
        if (intMod > 1) {
            return text.replace("[CURRENCY]", ColourUtil.colourise(intMod + " " + currencyType.getPlural(), ColourUtil.currency));
        } else if (intMod > 0) {
            return text.replace("[CURRENCY]", ColourUtil.colourise("a " + currencyType.getSingular(), ColourUtil.currency));
        } else {
            intMod = intMod * -1;
            if (intMod > 1) {
                return text.replace("[CURRENCY]", ColourUtil.colourise(intMod + " " + currencyType.getPlural(), ColourUtil.currency));
            } else if (intMod > 0) {
                return text.replace("[CURRENCY]", ColourUtil.colourise("a " + currencyType.getSingular(), ColourUtil.currency));
            } else {
                return text.replace("[CURRENCY]", ColourUtil.colourise("0 " + currencyType.getPlural(), ColourUtil.currency));
            }
        }
    }

    protected String replaceYou(String text, Player p, boolean observer) {
        if (observer) {
            return text.replace("[YOU]", ColourUtil.colourise(p.getName().toUpperCase(), ColourUtil.player)).replace("[you]", ColourUtil.colourise(p.getName(), ColourUtil.magenta)).replace("[You]", ColourUtil.colourise(p.getName(), ColourUtil.magenta));
        } else {
            return text.replace("[YOU]", "YOU").replace("[you]", "you").replace("[You]", "You");
        }
    }

    public TriggerResult cloneThis() {
        TriggerResult newClone = null;
        try {
            newClone = (TriggerResult) this.clone();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return newClone;
    }

    @Override
    public Object clone() {
        try {
            Object clone = super.clone();
            ((TriggerResult) clone).conditions = new ArrayList<TriggerCondition>();

            for (int c = 0; c < conditions.size(); c++) {
                ((TriggerResult) clone).conditions.add(conditions.get(c).cloneThis());
            }

            return clone;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }
}
